package app

import (
	"errors"
	"fmt"
	"log"
	"sieve_engine/execute/whatsapp/lib/noise"
	"sieve_engine/execute/whatsapp/lib/protocol/axolotl"
	db2 "sieve_engine/execute/whatsapp/lib/protocol/db"
	"sieve_engine/execute/whatsapp/lib/protocol/define"
	entity2 "sieve_engine/execute/whatsapp/lib/protocol/entity"
	handlers2 "sieve_engine/execute/whatsapp/lib/protocol/handlers"
	_interface "sieve_engine/execute/whatsapp/lib/protocol/iface"
	"sieve_engine/execute/whatsapp/lib/protocol/impl"
	"sieve_engine/execute/whatsapp/lib/protocol/msg"
	"sieve_engine/execute/whatsapp/lib/protocol/network"
	newxxmp2 "sieve_engine/execute/whatsapp/lib/protocol/newxxmp"
	node2 "sieve_engine/execute/whatsapp/lib/protocol/node"
	"sieve_engine/execute/whatsapp/lib/protocol/utils/promise"
	waver2 "sieve_engine/execute/whatsapp/lib/waver"
	"sieve_engine/execute/whatsapp/lib/wslog"
	"sync"
	"time"

	_ "github.com/mattn/go-sqlite3"
)

// WSAppEvent
type WSAppEvent struct {
	NewChatMessageNotify func(message *entity2.ChatMessage)
}

// SetNewMessageNotify 设置消息通知事件
func (w *WSAppEvent) SetNewMessageNotify(n func(message *entity2.ChatMessage)) {
	if n != nil {
		w.NewChatMessageNotify = n
	}
}

type LoginStatus int32

func (l LoginStatus) String() string {
	switch l {
	case Online:
		return "Online"
	case Drops:
		return "Drops"
	case Disconnect:
		return "Disconnect"
	case Connect:
		return "Connect"
	case AuthFailed:
		return "AuthFailed"
	case HandshakeFailed:
		return "HandshakeFailed"
	case Banned:
		return "Banned"
	case NetworkError:
		return "NetworkError"
	default:
		return ""
	}
}

const (
	_ LoginStatus = iota

	Online          // 上线 认证成功后上线(连接成功的)  1
	Drops           // 掉线 认证成功后掉线 （连接断开）  2
	AuthFailed      // 认证失败 (连接成功后认证失败)  3
	Banned          // 被禁止使用  4
	HandshakeFailed // 握手失败   5
	Connect         // 连接成功   6
	Disconnect      // 断开连接   7
	ParameterError  // 参数错误   8
	NetworkError    // 网络错误   9
)

// NewWaAppCli for test linhx
func MockNewWaAppCli(info *AccountInfo) *WaApp {
	platform := info.ClientPayload.UserAgent.GetPlatform().String()
	//如果为安卓普通版
	if platform == "ANDROID" {
		newxxmp2.SetWAXXMPVersion(waver2.NewWA52(info.version))
	} else if platform == "PLATFORM_10" {
		//安卓企业版
		newxxmp2.SetWAXXMPVersion(waver2.NewBusinessWA42())
	} else {
		return nil
	}
	// set log context
	info.SetLogCtx(define.LOGKEYSUSERNAME, info.GetUserName())
	// create whatsapp client
	w := &WaApp{loginPromise: impl.NewResultPromise(), AccountInfo: info, WSAppEvent: &WSAppEvent{}}
	return w
}

// NewWaAppCli
func NewWaAppCli(info *AccountInfo) *WaApp {
	platform := info.ClientPayload.UserAgent.GetPlatform().String()
	//如果为安卓普通版
	if platform == "ANDROID" {
		newxxmp2.SetWAXXMPVersion(waver2.NewWA52(info.version))
	} else if platform == "PLATFORM_10" {
		//安卓企业版
		newxxmp2.SetWAXXMPVersion(waver2.NewBusinessWA42())
	} else {
		return nil
	}
	// set log context
	info.SetLogCtx(define.LOGKEYSUSERNAME, info.GetUserName())
	// create whatsapp client
	w := &WaApp{loginPromise: impl.NewResultPromise(), AccountInfo: info, WSAppEvent: &WSAppEvent{}}
	// msg manager
	msgManager := msg.NewManager()
	w.msgManager = msgManager
	// set axolotl manager
	axolotlManager, err := axolotl.NewAxolotlManagerNew(info.GetUserName(), info.msgPubKey, info.msgPriKey, info.registrationId)
	if err != nil {
		wslog.GetLogger().Ctx(w.ctx).Info("waapp NewWaAppCli -> ", err)
		return nil
	}
	w.axolotlManager = axolotlManager
	// set network
	//payLoad, _ := proto.Marshal(info.clientPayload)
	w.netWork = network.NewNoiseClient(info.routingInfo, nil, noise.DHKey{}, w)
	segmentProcessor := w.netWork.GetSegment()
	// set node processor
	nodeProcessor := node2.NewMainNodeProcessor()
	w.node = nodeProcessor
	w.node.SetAxolotlManager(w.axolotlManager)
	w.node.SetMsgManager(w.msgManager)
	w.node.SetSegmentOutputProcessor(segmentProcessor)
	// handles
	handles := handlers2.NewHandles()
	// chat message handler
	chatMessageHandler := handlers2.NewChatMessageHandler(axolotlManager, nodeProcessor)
	chatMessageHandler.SetNotifyEvent(w)
	handles.AddHandler(chatMessageHandler)
	// notification handler
	//handles.AddHandler(handlers.NewNotificationHandler())
	// set handlers
	w.node.SetHandles(handles)
	return w
}

// WaApp
type WaApp struct {
	*AccountInfo
	*WSAppEvent

	loginStatus LoginStatus
	// module
	loginPromise   *impl.ResultPromise
	netWork        *network.NoiseNetWork
	axolotlManager *axolotl.Manager
	msgManager     *msg.Manager
	node           *node2.MainNodeProcessor
	// 重新登录等待 防止在没有登录完成时重复登录
	retryLoginWait sync.WaitGroup
}

// linhx added
func (w *WaApp) GetMainNodeProcessor() *node2.MainNodeProcessor {
	return w.node
}
func (w *WaApp) GetAxolotlManager() *axolotl.Manager {
	return w.axolotlManager
}

//linhx added end

func (w *WaApp) GetLoginStatus() LoginStatus {
	return w.loginStatus
}

// SetLoginStatus 设置登录状态
func (w *WaApp) SetLoginStatus(loginStatus LoginStatus) {
	w.loginStatus = loginStatus
	wslog.GetLogger().Ctx(w.ctx).Info("waapp SetLoginStatus -> ", w.loginStatus)
	//log.Println("waapp SetLoginStatus -> ", w.loginStatus)
	//linhx del
	/*db.PushQueue(
		db.PushMsg{
			UserName: w.ClientPayload.GetUsername(),
			Time:     time.Now().Unix(),
			Type:     db.Status.Number(),
			Data:     w.loginStatus,
		},
	)*/
}

func (w *WaApp) SetLoginStatusText(loginStatus LoginStatus, text string) {
	w.loginStatus = loginStatus
	wslog.GetLogger().Ctx(w.ctx).Info("waapp SetLoginStatusText -> ", w.loginStatus, text)
	//log.Println("waapp SetLoginStatusText -> ", w.loginStatus, text)
	//linhx del
	/*db.PushQueue(
		db.PushMsg{
			UserName: w.ClientPayload.GetUsername(),
			Time:     time.Now().Unix(),
			Type:     db.Status.Number(),
			Data:     w.loginStatus,
			Text:     text,
		},
	)*/
}

// WALogin
func (w *WaApp) WALogin() _interface.IPromise {
	// 当socket 没有连接或登录状态不为在线时可执行登录
	if !w.netWork.Connected() || w.loginStatus != Online {
		// 使用异步登录
		executor := func(resolve func(promise.Any), reject func(error)) {
			// time out
			go func() {
				<-time.After(time.Minute * 1)
				reject(errors.New("login time out"))
			}()
			// update handshake settings
			settings := w.GetLoginSettings()
			// start
			err := w.netWork.Connect(settings)
			if err != nil {
				reject(err)
				return
			}
		}
		// init login promise time out 30 second
		w.loginPromise.SetPromise(promise.New(executor))
	} else if w.netWork.Connected() && w.loginStatus == Online {
		// TODO 已经在线状态
		if w.loginPromise == nil {
			w.loginPromise.SuccessResolve("success")
		}
	}

	return w.loginPromise
}

// RetryLogin 重新登录
func (w *WaApp) RetryLogin() _interface.IPromise {
	// 不是掉线的不继续重新登录
	if w.loginStatus == Drops || w.loginStatus == Disconnect {
		// 重置
		w.Reset()
		// 等待十秒
		time.Sleep(time.Second * 10)
		return w.WALogin()
	}
	return nil
}

// TODO
func (w *WaApp) Reset() {
	// 重置网络
	w.netWork.Reset()
	// 重置 processor
	w.node.Reset()
}

// timingSendIqPing 定时发送 iq ping
func (w *WaApp) timingSendIqPing() {
	go func() {
		defer func() {
			if err := recover(); err != nil {
				fmt.Println("run web error:timingSendIqPing")
			}
		}()

		if w == nil && w.netWork == nil {
			return
		}
		if w.loginStatus == Disconnect {
			fmt.Println("账号退出---")
			return
		}
		// 检查网络连接情况
		if !w.netWork.Connected() {
			return
		}
		// 四分钟发送一次
		<-time.After(time.Minute * 4)
		// success
		successFunc := func(any promise.Any) {
			//log.Println("send iq ping resp")
			wslog.GetLogger().Ctx(w.ctx).Info("send iq ping resp ok")
			//linhx del
			/*db.PushQueue(
				db.PushMsg{
					Time:     time.Now().Unix(),
					UserName: w.ClientPayload.GetUsername(),
					Type:     db.System.Number(),
					Data:     "send iq ping resp succeed",
				},
			)*/
			w.timingSendIqPing()

			wslog.GetLogger().Ctx(w.ctx).Info("继续发送 ping")

		}
		// failure
		failureFunc := func(err error) {
			wslog.GetLogger().Ctx(w.ctx).Error("send ping failure ")
			//linhx del
			/*db.PushQueue(
				db.PushMsg{
					Time:     time.Now().Unix(),
					UserName: w.ClientPayload.GetUsername(),
					Type:     db.System.Number(),
					Data:     "send iq ping failure",
				},
			)*/
			//return
		}
		w.node.SendIqPing().
			SetListenHandler(successFunc, failureFunc)
	}()
}

// ===================== API =================================
// AddGroupMember 添加群成员
func (w *WaApp) AddGroupMember(groupId string, members ...string) _interface.IPromise {
	return w.node.SendAddGroup(groupId, members...)
}

// CreateGroup 创建群聊
func (w *WaApp) CreateGroup(subject string, participants []string) _interface.IPromise {
	return w.node.SendCreateGroup(w.GetUserName(), subject, participants)
}

// GetGroupMember 获取群成员
func (w *WaApp) GetGroupMember(groupId string) _interface.IPromise {
	grid := node2.NewJid(groupId)
	return w.node.SendGetGroupMember(grid.GroupId())
}

// GetGroupCode 获取群二维码
func (w *WaApp) GetGroupCode(groupId string) _interface.IPromise {
	return w.node.SendGetGroupCode(node2.NewJid(w.GetUserName()), node2.NewJid(groupId))
}

// CreateGroupAdmin  设置群管理&取消群管理
func (w *WaApp) CreateGroupAdmin(groupId string, opcode int32, toWid string) _interface.IPromise {
	if opcode == 0 {
		return w.node.CreateDemoteGroupAdmin(node2.NewJid(w.GetUserName()), node2.NewJid(groupId), node2.NewJid(toWid))
	}
	return w.node.CreateGroupAdmin(node2.NewJid(w.GetUserName()), node2.NewJid(groupId), node2.NewJid(toWid))
}

// SetGroupDesc  设置群描述
func (w *WaApp) SetGroupDesc(groupId string, desc string) _interface.IPromise {
	return w.node.SetGroupDesc(node2.NewJid(w.GetUserName()), node2.NewJid(groupId), desc)
}

// SendLogOutGroup 退出群组
func (w *WaApp) SendLogOutGroup(groupId string) _interface.IPromise {
	return w.node.CreateLogOutGroup(node2.NewJid(w.GetUserName()), node2.NewJid(groupId))
}

func (w *WaApp) SendPresencesSubscribeNew(u string) _interface.IPromise {
	// 发送订阅
	return w.node.SendPresencesSubscribeNew(u)
}

// SendPresencesSubscribe 发送订阅（发送消息前需要提前订阅指定用户）
func (w *WaApp) SendPresencesSubscribe(u string) _interface.IPromise {
	// 发送订阅
	presencesSubscribe := w.node.SendPresencesSubscribe(u)
	result, err := presencesSubscribe.GetResult()
	log.Println("presencesSubscribe ", result, err)
	return presencesSubscribe
}

// SendEncrypt 发送消息前会用到
func (w *WaApp) SendEncrypt(u string) _interface.IPromise {
	// 发送订阅
	node := w.node.SendEncrypt(node2.NewJid(u).Jid())
	return node
}

// SendGroupTextMessage 发送群聊消息
func (w *WaApp) SendGroupTextMessage(g string, msg string) (*msg.MySendMsg, error) {
	return w.node.SendTextGroupMessage(w.GetVeriFiledName(), node2.NewJid(w.GetUserName()), node2.NewJid(g), msg)
}

// SendTextMessage 发送文本消息
func (w *WaApp) SendTextMessage(u, msg string) (*msg.MySendMsg, error) {
	// send text
	return w.node.SendTextMessage(u, msg, w.GetVeriFiledName())
}

// SendNumberExistence 查询用户是否存在
func (w *WaApp) SendNumberExistence(number []string) (*msg.MySendMsg, error) {
	return w.node.SendNumberExistence(number)
}

// 发送图片消息
func (w *WaApp) SendImageMessage(u, base64, url, directPath string, mediaKey, fileEncSha256, FileSha256 []byte, FileLength uint64) (*msg.MySendMsg, error) {
	return w.node.SendImageMessage(u, base64, url, directPath, mediaKey, fileEncSha256, FileSha256, FileLength, w.GetVeriFiledName())
}

// SendGroupImageMessage 发送群聊图片消息
func (w *WaApp) SendGroupImageMessage(g string, base64, url, directPath string, mediaKey, fileEncSha256, FileSha256 []byte, FileLength uint64) (*msg.MySendMsg, error) {
	return w.node.SendImageGroupMessage(node2.NewJid(w.GetUserName()), node2.NewJid(g), base64, url, directPath, mediaKey, fileEncSha256, FileSha256, FileLength, w.GetVeriFiledName())
}

// SendSyncContacts 同步联系人
func (w *WaApp) SendSyncContacts(u []string) _interface.IPromise {
	return w.node.SendSyncContacts(u)
}

// SendSyncContactsAdd 同步联系人->扫对方二维码后发送 1
func (w *WaApp) SendSyncContactsAdd(u []string) _interface.IPromise {
	return w.node.SendSyncContactsAdd(u)
}

// SendSyncContactsInteractive 同步联系人-> 扫对方二维码后发送 2
func (w *WaApp) SendSyncContactsInteractive(u []string) _interface.IPromise {
	return w.node.SendSyncContactsInteractive(u)
}
func (w *WaApp) SyncAddOneContacts(u []string) _interface.IPromise {
	return w.node.SyncAddOneContacts(u)
}

// SyncAddScanContacts 扫号用
func (w *WaApp) SyncAddScanContacts(u []string) _interface.IPromise {
	return w.node.SyncAddScanContacts(u)
}

// SendChatState 发送聊天状态 paused -> Composing
func (w *WaApp) SendChatState(u string, isGroup, paused bool) {
	w.node.SendChatState(u, isGroup, paused)
}

// SendProfilePicture 设置头像
func (w *WaApp) SendProfilePicture(picture []byte) _interface.IPromise {
	return w.node.SendProfilePicture(w.GetUserName(), picture)
}

// SendGetQ 获取二维码
func (w *WaApp) SendGetQr() _interface.IPromise {
	return w.node.SendGetQr(w.GetUserName())
}

// SendNickName 设置名称
func (w *WaApp) SendNickName(name string) _interface.IPromise {
	return w.node.SendNickName(name)
}

// SetQrRevoke 重置二维码
func (w *WaApp) SetQrRevoke() _interface.IPromise {
	return w.node.SetQrRevoke(w.GetUserName())
}

// ScanCodeService 扫描二维码
func (w *WaApp) ScanCode(code string, opCode int32) _interface.IPromise {
	return w.node.ScanCode(code, opCode)
}

// InviteCode 邀请code
func (w *WaApp) InviteCode(code, toWid string) _interface.IPromise {
	return w.node.InviteCode(code, toWid)
}

// SendMediaConIq 获取cdn
func (w *WaApp) SendMediaConIq() _interface.IPromise {
	return w.node.SendMediaConIq()
}

// GetProfilePicture 获取用户头像
func (w *WaApp) GetProfilePicture(u string) _interface.IPromise {
	return w.node.SendGetProfilePicture(u)
}

// GetPreviewPicture 获取头像
func (w *WaApp) GetPreviewPicture(u string) _interface.IPromise {
	return w.node.SendGetProfilePreview(u)
}

// GetProfilePicture 设置个性签名
func (w *WaApp) SendSetState(content string) _interface.IPromise {
	return w.node.SendSetState(content)
}

// SendGetState 获取状态
func (w *WaApp) SendGetState(toWid string) _interface.IPromise {
	return w.node.SendGetState(w.GetUserName(), toWid)
}

// SendSnsText 发送文字动态
func (w *WaApp) SendSnsText(text string, participants []string) _interface.IPromise {
	return w.node.SendSnsText(w.GetVeriFiledName(), w.GetUserName(), text, participants)
}

// TwoVerify 二步安全验证
func (w *WaApp) TwoVerify(code, email string) _interface.IPromise {
	return w.node.Send2Fa(code, email)
}

// SendCategories 获取商业版类型列表
func (w *WaApp) SendCategories() _interface.IPromise {
	return w.node.SendCategories()
}

// SendBusinessProfile 设置商业版类型
func (w *WaApp) SendBusinessProfile(categoryId string) _interface.IPromise {
	return w.node.SendBusinessProfile(categoryId)
}

// SendBusinessPresenceAvailable 设置商业名字
func (w *WaApp) SendBusinessPresenceAvailable(name string) _interface.IPromise {
	return w.node.SendBusinessPresenceAvailable(name)
}

// GetQueryMyMsg
func (w *WaApp) GetQueryMyMsg() ([]msg.MySendMsg, error) {
	return nil, nil
}

// ===================== System settings =======================
// SetNetWorkProxy 设置代理
func (w *WaApp) SetNetWorkProxy(p string) {
	w.netWork.SetNetWorkProxy(p)
}
func (w *WaApp) GetNetWorkProxy() string {
	return w.netWork.GetNetWorkProxyStr()
}

// loginResultNotify 登录结果通知
func (w *WaApp) loginResultNotify(loginSuccess bool) {
	// TODO 通知登录结果
	if loginSuccess {
		// 服务器返回 success 表示登录成功
		//log.Println("上线成功")
		wslog.GetLogger().Ctx(w.ctx).Info("上线成功")
		w.SetLoginStatus(Online)

	} else {
		// 服务器返回 failure 表示认证失败
		//w.SetLoginStatus(AuthFailed)
		//log.Println("上线失败")
		wslog.GetLogger().Ctx(w.ctx).Info("上线失败")
		// 认证失败 不是返回的错误。握手失败或者socket断开才返回error
		w.loginPromise.SuccessResolve(w.loginStatus)
	}
}

// handlerNodeTree
func (w *WaApp) handleNodeTree(node *newxxmp2.Node) {
	if node == nil {
		return
	}
	defer func() {
		if r := recover(); r != nil {
			fmt.Printf("panic: %s\n", r)
		}
		return
	}()
	//fmt.Println("handlerNodeTree--->", node.GetTag())
	switch node.GetTag() {
	case "success":
		w.handleTagSuccess(node)
		break
	case "failure":
		w.handleTagFailure(*node)
		break
	default:
		//判断是否带有biz_status 商业版本初始化数据
		//bizNode:=node.GetChildrenByTag("biz_status")
		w.node.ProcessNode(node)
		/*if bizNode!=nil{
			fmt.Println("biz_status")
			w.node.SendCategories()
			w.node.SendPresenceAvailable("汽修学校教育001")
			w.node.SendBusinessProfile("1223524174334504")
			w.node.SendBusinessProfileTow(w.GetUserName())
		}*/
	}
}

// handleTagFailure
func (w *WaApp) handleTagFailure(node newxxmp2.Node) {
	//log.Println("WhatsApp login:", node.GetTag())
	wslog.GetLogger().Ctx(w.ctx).Info("handleTagFailure:", node.GetTag(), w.GetUserName())
	// 通知认证失败
	if w.loginPromise != nil {
		reason := node.GetAttributeByValue("reason")
		wslog.GetLogger().Ctx(w.ctx).Info("WhatsApp handleTagFailure reason:", reason)
		switch reason {
		case "503": //TODO 登录频繁了？
		case "401":
			w.SetLoginStatus(AuthFailed)
		case "403":
			// 账号被封
			w.SetLoginStatus(Banned)
		default:
			w.loginPromise.SuccessResolve(AuthFailed)
		}

	}

	// notify login failure
	w.loginResultNotify(false)
}

// handleTagSuccess
func (w *WaApp) handleTagSuccess(n *newxxmp2.Node) {
	wslog.GetLogger().Ctx(w.ctx).Info("WhatsApp login:", n.Tag, "create:", n.GetAttribute("creation").Value())
	// notify login success
	w.loginResultNotify(true)
	// 通知登录成功
	if w.loginPromise != nil {
		w.loginPromise.SuccessResolve(Online)
	}
	// send urn:xmpp:whatsapp:push
	w.node.SendIqConfig()
	//w.node.SendIqConfigOne()
	//w.node.SendIqConfigTwo()
	//<iq to='s.whatsapp.net' xmlns='urn:xmpp:whatsapp:account' type='get' id='4'><crypto action='create'><google>aISZpqfM2+JRNfND2XzsiNNZnUDewdG4fuIC9gM1jD4=</google></crypto></iq>
	//
	// send ping
	w.node.SendIqPing()
	w.timingSendIqPing()
	//如果是商业版
	if w.GetPlatform() == "PLATFORM_10" {
		go func() {
			defer func() {
				if err := recover(); err != nil {
					fmt.Println("run web error:SendGetVerifiedName")
				}
			}()
			//w.node.SendBusinessProfileTow(w.GetUserName())
			promise := w.node.SendGetVerifiedName(w.GetUserName())
			result, err := promise.GetResult()
			if err != nil {
				log.Fatalf("获取VerifiedName失败%s", err.Error())
			} else {
				iqResult := result.(entity2.IqResult)
				if iqResult.GetErrorEntityResult() != nil {
					log.Fatalf("获取VerifiedName失败iq-Result%s", err.Error())
				} else {
					if iqResult.VerifiedName != nil {
						number := iqResult.VerifiedName.GetVerifiedOne().GetVerifiedOne1()
						w.SetVeriFiledName(number)
					}
				}
			}
		}()
	}
	// send available
	w.node.SendPresenceAvailable()

	// 检查是否有 未上传的identity key
	if w.axolotlManager.HasUnsentPreKeys() {
		w.node.SendActive()
		// upload pre keys
		err := w.node.SendSetEncryptKeys()
		if err != nil {
			log.Println("update pre keys err", err)
			return
		}

	}

	// test

	//syncContact := w.node.SendSyncContacts([]string{
	//	"+5538991026786",
	//})
	//result, _ := syncContact.GetResult()
	//iqResult := result.(entity.IqResult)
	//for _, info := range iqResult.GetUSyncContacts() {
	//	log.Println(info.Jid(), info.Status(), info.Contact())
	//	_ = w.SendTextMessage(info.Jid(), "qqqq")
	//}
	//time.Sleep(time.Second * 10)
	//w.AddGroupMember("6283827948009-1618049667", "84878954360")

	//presencesSubscribe := w.node.SendPresencesSubscribe("84878185730")
	//result, err := presencesSubscribe.GetResult()
	//log.Println("presencesSubscribe ", result, err)
	//group := w.node.SendCreateGroup("6283827948009", "测试建群", []string{"8617607567005", "84878185730"})
	//d, _ := group.GetResult()
	//result := d.(_struct.IqResult)
	//
	//log.Println(result.String())
	//w.node.SendTextGroupMessage(node.NewJid(""), node.NewJid("8617607567005-1619075992"), "真棒")
	////w.node.SendTextGroupMessage(node.NewJid("6283827948009-1618049667"),"")
	//for i := 0; i < 1; i++ {
	//	_ = w.SendTextMessage("5538991026786", "qqqq")
	//}

	/*iqUserKeys := w.node.SendGetIqUserKeys([]string{"8617607567005"})
	iqUserKeys.SetListenHandler(func(any promise.Any) {
		log.Println("iqUserKeys : ", any)
	}, nil)*/
}

// 消息回調通知redis
func (w *WaApp) NotifyHandleResult(any ...interface{}) {
	if len(any) <= 0 || any[0] == nil {
		return
	}
	// handler result
	if handle, ok := any[0].(*handlers2.HandleResult); ok {
		result := handle.GetResult()
		//fmt.Println("----------->消息通知", result)
		switch result.(type) {
		case error:
		case *entity2.ChatMessage:
			if w.NewChatMessageNotify != nil {
				message := result.(*entity2.ChatMessage)
				//如果是消息媒体类型
				pushData := entity2.RespMessage{
					T:           message.T(),
					Participant: message.Participant(),
					From:        message.From(),
					ContextType: message.ContextType(),
					Id:          message.Id(),
				}

				if message.ContextType() == "media" {
					if message.GetMessage() != nil {
						pushData.Message = entity2.ParseProtoMessage(message.GetMessage())
					}
				} else {
					pushData.Message = entity2.ParseProtoMessage(message.GetMessage())
				}
				db2.PushQueue(
					db2.PushMsg{
						Time:     time.Now().Unix(),
						UserName: w.ClientPayload.GetUsername(),
						Type:     db2.Msg.Number(),
						Data:     pushData,
					},
				)
				w.NewChatMessageNotify(result.(*entity2.ChatMessage))
			}
		case *entity2.Notification:
			fmt.Println("-------------notification", result.(*entity2.Notification))
		}
	}
}

// ======================= network ============================
func (w *WaApp) OnConnect() {
	defer func() {
		if err := recover(); err != nil {
			fmt.Println("run web error:OnConnect")
		}
	}()
	// 设置登录状态为连接
	w.SetLoginStatus(Connect)
	//log.Println("连接成功")
	wslog.GetLogger().Ctx(w.ctx).Println("OnConnect success!")

	// 重置 segment processor
	segmentProcessor := w.netWork.GetSegment()
	w.node.SetSegmentOutputProcessor(segmentProcessor)
}
func (w *WaApp) OnRecvData(d []byte) {
	defer func() {
		if err := recover(); err != nil {
			fmt.Println("run web error:OnRecvData")
		}
	}()
	decodeNode, err := newxxmp2.XMMPDecodeNode(d)
	if err != nil {
		//log.Println("WaApp OnRecvData DecodeNode error:", err)
		wslog.GetLogger().Ctx(w.ctx).Error("WaApp OnRecvData DecodeNode error:", err)
		return
	}
	if decodeNode == nil {
		wslog.GetLogger().Ctx(w.ctx).Error("WaApp decodeNode decodeNode error:", decodeNode)
		return
	}
	//log.Println("DecodeNode:", decodeNode.GetString())
	//TODO linhx del log
	//wslog.GetLogger().Ctx(w.ctx).Info("onRecvData", "decode node", decodeNode.GetString())
	go w.handleNodeTree(decodeNode)
}
func (w *WaApp) OnHandShakeFailed(err error) {
	// 出现握手失败的表示认证失败
	//log.Println("onHandShakeFailed ", "出现握手失败 -> ", err)
	wslog.GetLogger().Ctx(w.ctx).Error("onHandShakeFailed ", "出现握手失败 -> ", err)
	w.SetLoginStatus(HandshakeFailed)
	//TODO linhx add
	w.node.Close()
	//TODO linhx add end
	w.loginPromise.Reject(err)
}
func (w *WaApp) OnError(err error) {
	wslog.GetLogger().Ctx(w.ctx).Error("OnError", " phone:", w.GetUserName(), " loginStatus:", w.loginStatus, " 发送错误:", err)
	//log.Println("waapp.go onError un:", w.GetUserName(), " loginStatus:", w.loginStatus, " 发送错误:", err)
	w.loginPromise.Reject(err)
}
func (w *WaApp) OnDisconnect() {
	//log.Println("断开连接", "当前用户状态:", w.loginStatus)
	wslog.GetLogger().Ctx(w.ctx).Info("断开连接", " phone:", w.GetUserName(), " 当前用户状态:", w.loginStatus)
	// 被禁止
	if w.loginStatus == Banned {
		//推送过去上线失败，断开连接
		w.SetLoginStatusText(Banned, "Banned账号被封!")
		//TODO linhx add
		w.node.Close()
		w.loginPromise.Reject(errors.New("OnDisconnect() -> Banned账号被封!"))
		//TODO linhx add end
		return
	}
	//TODO linhx add
	if w.loginStatus == AuthFailed {
		w.SetLoginStatusText(AuthFailed, "认证失败!")
		w.node.Close()
		w.loginPromise.Reject(errors.New("OnDisconnect() -> 认证失败!"))
		return
	}
	//TODO linhx add end
	if w.loginStatus == Drops {
		w.SetLoginStatus(Drops)
		w.retryLoginWait.Wait()
	}
	// 如果上次登录状态是在线的，断开连接后将状态重置为掉线
	if w.loginStatus == Online {
		w.SetLoginStatus(Drops)
		//log.Println("OnDisconnect", "开始重新尝试上线")
		//// 防止重复重新登录
		//w.retryLoginWait.AddWa(1)
		//defer w.retryLoginWait.Done()
		//// TODO 可进行重连
		//retryLoginResult := w.RetryLogin()
		//if retryLoginResult != nil {
		//	_, err := retryLoginResult.GetResult()
		//	if err != nil {
		//		//重新上线失败，推送给客户端
		//		wslog.GetLogger().Ctx(w.ctx).Error("retryLoginResult:", err)
		//		//推送过去上线失败，断开连接
		//		w.SetLoginStatusText(Disconnect, err.Error())
		//		return
		//	}
		//	log.Println("重新上线成功！")
		//} else {
		//	//推送过去上线失败，断开连接
		//	w.SetLoginStatusText(Disconnect, "retryLoginResult is nil！")
		//	log.Println("retryLoginResult is nil！")
		//}
	} else {
		// 如果没有登录成功置登录为断开socket 连接
		msg := "断开连接,当前用户状态:" + w.loginStatus.String()
		w.SetLoginStatusText(Disconnect, msg)
		w.loginPromise.Reject(errors.New("disconnect"))
	}
}
